/***************************************
 *
 *     与应用层交互
 *
 **************************************/

#include "kernel_operation.h"

DemoShareData* g_shared_data = nullptr;

int MotorFaultExucteCnt = 0;

int counter = 0;
int outIndex = 0;
int value = 0x01;

// 主要操作
int MainIOTask()
{
    if (g_shared_data != nullptr)
    {
        //KS_printK("_dataSetCallBack:  %d", g_shared_data->io_app_pod.IO_value_out);
    }

    counter++;
    if (counter >= 500)
    {
        counter = 0;
        outIndex++;

        if (outIndex >= 16)
        {
            outIndex = 0;
        }
        if (g_shared_data != nullptr)
        {
            *g_shared_data->io_system_pod.IO_value_out = value << outIndex;
        }
    }
    return 0;
}

// 初始化
extern "C" __declspec(dllexport) KSError __stdcall InitFunction(void* pArgs, void* /*pContext*/)
{
    //KS_printK("Kithara Kernel Init");

    //初始化全局共享内存指针
    g_shared_data = reinterpret_cast<DemoShareData*>(pArgs);
    return KS_OK;
}

// 计时器回调，定时下发EtherCAT通信数据包
extern "C" __declspec(dllexport) KSError __stdcall TimerCallBack(void* pArgs, void* /*pContext*/)
{
    KSError error = KS_OK;
    error = KS_postEcatDataSet(g_shared_data->data_set_handle, 0);
    if (error != KS_OK)
    {
        KS_printK("TimerCallBack Error");
        //return error;
    }

    //KS_printK("TimerCallBack");

    return KS_OK;
}

// 数据集回调，更新完EtherCAT通信数据包后，触发
extern "C" __declspec(dllexport) KSError __stdcall DataSetCallBack(void* pArgs, void* /*pContext*/)
{
    KSError error = KS_readEcatDataSet(g_shared_data->data_set_handle, 0);
    if (error != KS_OK)
    {
        //KS_printK("-------------  DataSetCallBack Error");
        if (KSERROR_CODE(error) == KSERROR_NO_RESPONSE) // 有些从属设备需要更多时间才能完全进入 SAFEOP 并回答 DataSet
        {
            return KS_OK;
        }
        return error;  // 不可以返回 failed,否则数据集回调停止
    }

    //KS_printK("DataSetCallBack");

    // 执行相关操作
    //MainIOTask();
    return KS_OK;
}

// 主站错误回调
extern "C" __declspec(dllexport) KSError __stdcall MasterErrorCallBack(void* pArgs, void* /*pContext*/)
{
    KS_printK("MasterErrorCallBack");
    return KS_OK;
}

// 拓扑结构变化回调
extern "C" __declspec(dllexport) KSError __stdcall TopologyCallBack(void* pArgs, void* pContext)
{
    const auto user_context = (EcatTopologyUserContext*)pContext;
    KS_printK("--------------------------- slavesOnline: %d", user_context->slavesOnline);
    KS_printK("--------------------------- slavesCreated: %d", user_context->slavesCreated);
    KS_printK("--------------------------- hSlave: %d", user_context->hSlave);

    // 根据上下文信息，处理从站状态变化
    if (user_context->ctxType == KS_ECAT_TOPOLOGY_CHANGE)
    {
        // 从站上线
        if (user_context->reason == KS_ECAT_TOPOLOGY_SLAVE_ONLINE)
        {
            KSEcatMasterState master_stater;
            master_stater.structSize = sizeof(KSEcatMasterState); // 特别注意设置结构体大小
            if (KSError error = KS_queryEcatMasterState(user_context->hMaster, &master_stater, 0); error == KS_OK)
            {
                error = KS_changeEcatState(user_context->hMaster, KS_ECAT_STATE_SAFEOP, 0);
                if (error != KS_OK)
                {
                    KS_printK("--------------------------- KS_changeEcatState KS_ECAT_STATE_SAFEOP Error");
                }

                error = KS_changeEcatState(user_context->hSlave, KS_ECAT_STATE_OP, 0);
                if (error != KS_OK)
                {
                    KS_printK("--------------------------- KS_changeEcatState KS_ECAT_STATE_OP Error");
                }
            }
        }
        else if (user_context->reason == KS_ECAT_TOPOLOGY_SLAVE_OFFLINE) // 从站下线
        {
            if (const KSError error = KS_changeEcatState(user_context->hMaster, KS_ECAT_STATE_INIT, 0); error != KS_OK)
            {
                KS_printK("--------------------------- KS_changeEcatState KS_ECAT_STATE_INIT Error");
            }
        }
    }

    return KS_OK;
}

#define WIN32_LEAN_AND_MEAN
#pragma pack(push, 8)

#include <Windows.h>

#pragma pack(pop)

// DLL如何，保证正常编译，在Kithara中并无作用
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID pReserved)
{
    return TRUE;
}
